1 /* 2 * This file is part of gtkD. 3 * 4 * gtkD is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * gtkD is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with gtkD; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 20 // generated automatically - do not change 21 // find conversion definition on APILookup.txt 22 // implement new conversion functionalities on the wrap.utils pakage 23 24 25 module glib.Spawn; 26 27 private import core.stdc.stdio; 28 private import core.stdc.string; 29 private import core.thread; 30 private import glib.ErrorG; 31 private import glib.GException; 32 private import glib.Str; 33 private import glib.c.functions; 34 public import glib.c.types; 35 private import std.string; 36 private import std.traits; 37 38 39 /** */ 40 public class Spawn 41 { 42 //we need fdopen. 43 version(Posix) 44 { 45 private import core.sys.posix.stdio; 46 } 47 //fdopen for Windows is defined in glib.c.types. 48 49 string workingDirectory = "."; 50 string[] argv; 51 string[] envp; 52 GSpawnFlags flags = SpawnFlags.SEARCH_PATH; 53 GSpawnChildSetupFunc childSetup; 54 void* userData; 55 GPid childPid; 56 FILE* standardInput; 57 FILE* standardOutput; 58 FILE* standardError; 59 GError* error; 60 int stdIn; 61 int stdOut; 62 int stdErr; 63 64 // for commandLineSync 65 int exitStatus; 66 char* strOutput; 67 char* strError; 68 69 alias bool delegate(Spawn) ChildWatch; 70 ChildWatch externalWatch; 71 72 /** 73 * Creates a Spawn for execution. 74 */ 75 public this(string program, string[] envp=null) 76 { 77 argv ~= program; 78 this.envp = envp; 79 } 80 81 /** 82 * Creates a Spawn for execution. 83 */ 84 public this(string[] program, string[] envp=null) 85 { 86 argv = program; 87 this.envp = envp; 88 } 89 90 /** 91 * Adds a delegate to be notified on the end of the child process. 92 * Params: 93 * dlg = 94 */ 95 public void addChildWatch(ChildWatch dlg) 96 { 97 externalWatch = dlg; 98 } 99 100 /** 101 * Closes all open streams and child process. 102 */ 103 public void close() 104 { 105 if (stdIn != 0 ) 106 { 107 fclose(standardInput); 108 stdIn = 0; 109 } 110 if (stdOut != 0 ) 111 { 112 fclose(standardOutput); 113 stdOut = 0; 114 } 115 if (stdErr != 0 ) 116 { 117 fclose(standardError); 118 stdErr = 0; 119 } 120 static if ( isPointer!(GPid) ) 121 { 122 if ( childPid !is null ) 123 { 124 closePid(childPid); 125 childPid = null; 126 } 127 } 128 else 129 { 130 if ( childPid != 0 ) 131 { 132 closePid(childPid); 133 childPid = 0; 134 } 135 } 136 } 137 138 /** 139 * Adds a parameter to the execution program 140 */ 141 public void addParm(string parm) 142 { 143 argv ~= parm; 144 } 145 146 /** 147 * Gets the last error message 148 */ 149 public string getLastError() 150 { 151 if ( error != null ) 152 { 153 return Str.toString(error.message); 154 } 155 return ""; 156 } 157 158 /** 159 * Executes the prepared process 160 */ 161 public int execAsyncWithPipes( 162 ChildWatch externalWatch = null, 163 bool delegate(string) readOutput = null, 164 bool delegate(string) readError = null ) 165 { 166 int result = g_spawn_async_with_pipes( 167 Str.toStringz(workingDirectory), 168 Str.toStringzArray(argv), 169 Str.toStringzArray(envp), 170 flags, 171 childSetup, 172 userData, 173 &childPid, 174 &stdIn, 175 &stdOut, 176 &stdErr, 177 &error 178 ); 179 180 if ( result != 0 ) 181 { 182 this.externalWatch = externalWatch; 183 g_child_watch_add(childPid, cast(GChildWatchFunc)(&childWatchCallback), cast(void*)this); 184 standardInput = fdopen(stdIn, Str.toStringz("w")); 185 standardOutput = fdopen(stdOut, Str.toStringz("r")); 186 standardError = fdopen(stdErr, Str.toStringz("r")); 187 188 if ( readOutput !is null ) 189 { 190 (new ReadFile(standardOutput, readOutput)).start(); 191 } 192 if ( readError !is null ) 193 { 194 (new ReadFile(standardError, readError)).start(); 195 } 196 } 197 198 return result; 199 } 200 201 class ReadFile : Thread 202 { 203 bool delegate(string) read; 204 FILE* file; 205 206 int lineCount; 207 208 this(FILE* file, bool delegate (string) read ) 209 { 210 this.file = file; 211 this.read = read; 212 213 super(&run); 214 } 215 216 public void run() 217 { 218 string line = readLine(file); 219 while( line !is null ) 220 { 221 ++lineCount; 222 if ( read !is null ) 223 { 224 read(line); 225 } 226 line = readLine(file); 227 } 228 } 229 } 230 231 private string readLine(FILE* stream, int max=4096) 232 { 233 if ( feof(stream) ) 234 { 235 if ( externalWatch !is null ) 236 { 237 externalWatch(this); 238 } 239 return null; 240 } 241 string line; 242 line.length = max+1; 243 char* lineP = fgets(Str.toStringz(line), max, stream); 244 if ( lineP is null ) 245 { 246 return ""; 247 } 248 size_t l = strlen(line.ptr); 249 if ( l > 0 ) --l; 250 251 return line[0..l]; 252 } 253 254 extern(C) static void childWatchCallback(int pid, int status, Spawn spawn) 255 { 256 //writefln("Spawn.childWatchCallback %s %s", pid, status); 257 spawn.exitStatus = status; 258 if ( spawn.externalWatch !is null ) 259 { 260 spawn.externalWatch(spawn); 261 } 262 spawn.close(); 263 } 264 265 266 public bool endOfOutput() 267 { 268 if ( standardOutput is null ) return true; 269 return feof(standardOutput) != 0; 270 } 271 272 public bool endOfError() 273 { 274 if ( standardError is null ) return true; 275 return feof(standardError) != 0; 276 } 277 278 string getOutputString() 279 { 280 return Str.toString(strOutput); 281 } 282 283 string getErrorString() 284 { 285 return Str.toString(strError); 286 } 287 288 int getExitStatus() 289 { 290 return exitStatus; 291 } 292 293 /** 294 * Executes a command synchronasly and 295 * optionally calls delegates for sysout, syserr and end of job 296 * 297 */ 298 public int commandLineSync( 299 ChildWatch externalWatch = null, 300 bool delegate(string) readOutput = null, 301 bool delegate(string) readError = null ) 302 { 303 string commandLine; 304 foreach ( count, string arg; argv) 305 { 306 if ( count > 0 ) 307 { 308 commandLine ~= ' '; 309 } 310 commandLine ~= arg; 311 } 312 int status = g_spawn_command_line_sync( 313 Str.toStringz(commandLine), 314 &strOutput, 315 &strError, 316 &exitStatus, 317 &error); 318 if ( readOutput != null ) 319 { 320 foreach ( string line ; splitLines(Str.toString(strOutput)) ) 321 { 322 readOutput(line); 323 } 324 } 325 if ( readError != null ) 326 { 327 foreach ( string line ; splitLines(Str.toString(strError)) ) 328 { 329 readError(line); 330 } 331 } 332 if ( externalWatch != null ) 333 { 334 externalWatch(this); 335 } 336 return status; 337 } 338 339 /** 340 */ 341 342 /** 343 * Executes a child program asynchronously. 344 * 345 * See g_spawn_async_with_pipes() for a full description; this function 346 * simply calls the g_spawn_async_with_pipes() without any pipes. 347 * 348 * You should call g_spawn_close_pid() on the returned child process 349 * reference when you don't need it any more. 350 * 351 * If you are writing a GTK application, and the program you are spawning is a 352 * graphical application too, then to ensure that the spawned program opens its 353 * windows on the right screen, you may want to use #GdkAppLaunchContext, 354 * #GAppLaunchContext, or set the %DISPLAY environment variable. 355 * 356 * Note that the returned @child_pid on Windows is a handle to the child 357 * process and not its identifier. Process handles and process identifiers 358 * are different concepts on Windows. 359 * 360 * Params: 361 * workingDirectory = child's current working 362 * directory, or %NULL to inherit parent's 363 * argv = child's argument vector 364 * envp = child's environment, or %NULL to inherit parent's 365 * flags = flags from #GSpawnFlags 366 * childSetup = function to run in the child just before exec() 367 * userData = user data for @child_setup 368 * childPid = return location for child process reference, or %NULL 369 * 370 * Returns: %TRUE on success, %FALSE if error is set 371 * 372 * Throws: GException on failure. 373 */ 374 public static bool async(string workingDirectory, string[] argv, string[] envp, GSpawnFlags flags, GSpawnChildSetupFunc childSetup, void* userData, out GPid childPid) 375 { 376 GError* err = null; 377 378 auto __p = g_spawn_async(Str.toStringz(workingDirectory), Str.toStringzArray(argv), Str.toStringzArray(envp), flags, childSetup, userData, &childPid, &err) != 0; 379 380 if (err !is null) 381 { 382 throw new GException( new ErrorG(err) ); 383 } 384 385 return __p; 386 } 387 388 /** 389 * An old name for g_spawn_check_wait_status(), deprecated because its 390 * name is misleading. 391 * 392 * Despite the name of the function, @wait_status must be the wait status 393 * as returned by g_spawn_sync(), g_subprocess_get_status(), `waitpid()`, 394 * etc. On Unix platforms, it is incorrect for it to be the exit status 395 * as passed to `exit()` or returned by g_subprocess_get_exit_status() or 396 * `WEXITSTATUS()`. 397 * 398 * Deprecated: Use g_spawn_check_wait_status() instead, and check whether your code is conflating wait and exit statuses. 399 * 400 * Params: 401 * waitStatus = A status as returned from g_spawn_sync() 402 * 403 * Returns: %TRUE if child exited successfully, %FALSE otherwise (and 404 * @error will be set) 405 * 406 * Since: 2.34 407 * 408 * Throws: GException on failure. 409 */ 410 public static bool checkExitStatus(int waitStatus) 411 { 412 GError* err = null; 413 414 auto __p = g_spawn_check_exit_status(waitStatus, &err) != 0; 415 416 if (err !is null) 417 { 418 throw new GException( new ErrorG(err) ); 419 } 420 421 return __p; 422 } 423 424 /** 425 * On some platforms, notably Windows, the #GPid type represents a resource 426 * which must be closed to prevent resource leaking. g_spawn_close_pid() 427 * is provided for this purpose. It should be used on all platforms, even 428 * though it doesn't do anything under UNIX. 429 * 430 * Params: 431 * pid = The process reference to close 432 */ 433 public static void closePid(GPid pid) 434 { 435 g_spawn_close_pid(pid); 436 } 437 438 /** 439 * A simple version of g_spawn_async() that parses a command line with 440 * g_shell_parse_argv() and passes it to g_spawn_async(). 441 * 442 * Runs a command line in the background. Unlike g_spawn_async(), the 443 * %G_SPAWN_SEARCH_PATH flag is enabled, other flags are not. Note 444 * that %G_SPAWN_SEARCH_PATH can have security implications, so 445 * consider using g_spawn_async() directly if appropriate. Possible 446 * errors are those from g_shell_parse_argv() and g_spawn_async(). 447 * 448 * The same concerns on Windows apply as for g_spawn_command_line_sync(). 449 * 450 * Params: 451 * commandLine = a command line 452 * 453 * Returns: %TRUE on success, %FALSE if error is set 454 * 455 * Throws: GException on failure. 456 */ 457 public static bool commandLineAsync(string commandLine) 458 { 459 GError* err = null; 460 461 auto __p = g_spawn_command_line_async(Str.toStringz(commandLine), &err) != 0; 462 463 if (err !is null) 464 { 465 throw new GException( new ErrorG(err) ); 466 } 467 468 return __p; 469 } 470 471 /** 472 * A simple version of g_spawn_sync() with little-used parameters 473 * removed, taking a command line instead of an argument vector. 474 * 475 * See g_spawn_sync() for full details. 476 * 477 * The @command_line argument will be parsed by g_shell_parse_argv(). 478 * 479 * Unlike g_spawn_sync(), the %G_SPAWN_SEARCH_PATH flag is enabled. 480 * Note that %G_SPAWN_SEARCH_PATH can have security implications, so 481 * consider using g_spawn_sync() directly if appropriate. 482 * 483 * Possible errors are those from g_spawn_sync() and those 484 * from g_shell_parse_argv(). 485 * 486 * If @wait_status is non-%NULL, the platform-specific status of 487 * the child is stored there; see the documentation of 488 * g_spawn_check_wait_status() for how to use and interpret this. 489 * On Unix platforms, note that it is usually not equal 490 * to the integer passed to `exit()` or returned from `main()`. 491 * 492 * On Windows, please note the implications of g_shell_parse_argv() 493 * parsing @command_line. Parsing is done according to Unix shell rules, not 494 * Windows command interpreter rules. 495 * Space is a separator, and backslashes are 496 * special. Thus you cannot simply pass a @command_line containing 497 * canonical Windows paths, like "c:\\program files\\app\\app.exe", as 498 * the backslashes will be eaten, and the space will act as a 499 * separator. You need to enclose such paths with single quotes, like 500 * "'c:\\program files\\app\\app.exe' 'e:\\folder\\argument.txt'". 501 * 502 * Params: 503 * commandLine = a command line 504 * standardOutput = return location for child output 505 * standardError = return location for child errors 506 * waitStatus = return location for child wait status, as returned by waitpid() 507 * 508 * Returns: %TRUE on success, %FALSE if an error was set 509 * 510 * Throws: GException on failure. 511 */ 512 public static bool commandLineSync(string commandLine, out string standardOutput, out string standardError, out int waitStatus) 513 { 514 char* outstandardOutput = null; 515 char* outstandardError = null; 516 GError* err = null; 517 518 auto __p = g_spawn_command_line_sync(Str.toStringz(commandLine), &outstandardOutput, &outstandardError, &waitStatus, &err) != 0; 519 520 if (err !is null) 521 { 522 throw new GException( new ErrorG(err) ); 523 } 524 525 standardOutput = Str.toString(outstandardOutput); 526 standardError = Str.toString(outstandardError); 527 528 return __p; 529 } 530 531 /** */ 532 public static GQuark errorQuark() 533 { 534 return g_spawn_error_quark(); 535 } 536 537 /** */ 538 public static GQuark exitErrorQuark() 539 { 540 return g_spawn_exit_error_quark(); 541 } 542 543 /** 544 * Executes a child synchronously (waits for the child to exit before returning). 545 * 546 * All output from the child is stored in @standard_output and @standard_error, 547 * if those parameters are non-%NULL. Note that you must set the 548 * %G_SPAWN_STDOUT_TO_DEV_NULL and %G_SPAWN_STDERR_TO_DEV_NULL flags when 549 * passing %NULL for @standard_output and @standard_error. 550 * 551 * If @wait_status is non-%NULL, the platform-specific status of 552 * the child is stored there; see the documentation of 553 * g_spawn_check_wait_status() for how to use and interpret this. 554 * On Unix platforms, note that it is usually not equal 555 * to the integer passed to `exit()` or returned from `main()`. 556 * 557 * Note that it is invalid to pass %G_SPAWN_DO_NOT_REAP_CHILD in 558 * @flags, and on POSIX platforms, the same restrictions as for 559 * g_child_watch_source_new() apply. 560 * 561 * If an error occurs, no data is returned in @standard_output, 562 * @standard_error, or @wait_status. 563 * 564 * This function calls g_spawn_async_with_pipes() internally; see that 565 * function for full details on the other parameters and details on 566 * how these functions work on Windows. 567 * 568 * Params: 569 * workingDirectory = child's current working 570 * directory, or %NULL to inherit parent's 571 * argv = child's argument vector, which must be non-empty and %NULL-terminated 572 * envp = child's environment, or %NULL to inherit parent's 573 * flags = flags from #GSpawnFlags 574 * childSetup = function to run in the child just before exec() 575 * userData = user data for @child_setup 576 * standardOutput = return location for child output, or %NULL 577 * standardError = return location for child error messages, or %NULL 578 * waitStatus = return location for child wait status, as returned by waitpid(), or %NULL 579 * 580 * Returns: %TRUE on success, %FALSE if an error was set 581 * 582 * Throws: GException on failure. 583 */ 584 public static bool sync(string workingDirectory, string[] argv, string[] envp, GSpawnFlags flags, GSpawnChildSetupFunc childSetup, void* userData, out string standardOutput, out string standardError, out int waitStatus) 585 { 586 char* outstandardOutput = null; 587 char* outstandardError = null; 588 GError* err = null; 589 590 auto __p = g_spawn_sync(Str.toStringz(workingDirectory), Str.toStringzArray(argv), Str.toStringzArray(envp), flags, childSetup, userData, &outstandardOutput, &outstandardError, &waitStatus, &err) != 0; 591 592 if (err !is null) 593 { 594 throw new GException( new ErrorG(err) ); 595 } 596 597 standardOutput = Str.toString(outstandardOutput); 598 standardError = Str.toString(outstandardError); 599 600 return __p; 601 } 602 603 /** 604 * Executes a child program asynchronously. 605 * 606 * Identical to g_spawn_async_with_pipes_and_fds() but with `n_fds` set to zero, 607 * so no FD assignments are used. 608 * 609 * Params: 610 * workingDirectory = child's current working directory, or %NULL to inherit parent's, in the GLib file name encoding 611 * argv = child's argument vector, in the GLib file name encoding; 612 * it must be non-empty and %NULL-terminated 613 * envp = child's environment, or %NULL to inherit parent's, in the GLib file name encoding 614 * flags = flags from #GSpawnFlags 615 * childSetup = function to run in the child just before exec() 616 * userData = user data for @child_setup 617 * childPid = return location for child process ID, or %NULL 618 * stdinFd = file descriptor to use for child's stdin, or `-1` 619 * stdoutFd = file descriptor to use for child's stdout, or `-1` 620 * stderrFd = file descriptor to use for child's stderr, or `-1` 621 * 622 * Returns: %TRUE on success, %FALSE if an error was set 623 * 624 * Since: 2.58 625 * 626 * Throws: GException on failure. 627 */ 628 public static bool asyncWithFds(string workingDirectory, string[] argv, string[] envp, GSpawnFlags flags, GSpawnChildSetupFunc childSetup, void* userData, out GPid childPid, int stdinFd, int stdoutFd, int stderrFd) 629 { 630 GError* err = null; 631 632 auto __p = g_spawn_async_with_fds(Str.toStringz(workingDirectory), Str.toStringzArray(argv), Str.toStringzArray(envp), flags, childSetup, userData, &childPid, stdinFd, stdoutFd, stderrFd, &err) != 0; 633 634 if (err !is null) 635 { 636 throw new GException( new ErrorG(err) ); 637 } 638 639 return __p; 640 } 641 }